<template>
  <div class="operation-content">
    <div class="step-content">
      <tool-button type="primary" @click="start" :disabled="activeStep !== 0">开始执行</tool-button>
    </div>
    <!-- 本地打包 -->
    <div class="step-content">
      <button class="step-button" :class="{ 'active': activeStep >= 1 }">
        <transition name = "fade">
          <icon-font v-show="activeStep === 1" class="iconfont" name="loading"></icon-font>
        </transition>
        <transition name = "fade">
          <icon-font v-show="activeStep > 1" class="iconfont actived" name="select"></icon-font>
        </transition>
        <span>本地打包</span>
      </button>
    </div>
    <!-- 上传到服务器 -->
    <div class="step-content">
      <button class="step-button" :class="{ 'active': activeStep >= 2 }">
        <transition name = "fade">
          <icon-font v-show="activeStep === 2" class="iconfont" name="loading"></icon-font>
        </transition>
        <transition name = "fade">
          <icon-font v-show="activeStep > 2" class="iconfont actived" name="select"></icon-font>
        </transition>
        <span>上传到服务器</span>
      </button>
    </div>
    <!-- 重启Web服务器 -->
    <div class="step-content">
      <button class="step-button" :class="{ 'active': activeStep >= 3 }">
        <transition name = "fade">
          <icon-font v-show="activeStep === 3" class="iconfont" name="loading"></icon-font>
        </transition>
        <transition name = "fade">
          <icon-font v-show="activeStep > 3" class="iconfont actived" name="select"></icon-font>
        </transition>
        <span>重启Web服务器</span>
      </button>
    </div>
  </div>
</template>

<script>
import { exec } from 'child_process'
import Client from 'ssh2-sftp-client'
import SSH2Promise from 'ssh2-promise'
import { mapActions } from 'vuex'
export default {
  props: {
    // 选择的列表
    selectList: {
      type: Array,
      default: []
    }
  },
  data () {
    return {
      activeStep: 0
    }
  },
  methods: {
    ...mapActions([
      'addLog',
      'addLogWarning',
      'addLogError',
      'addLogSuccess',
      'clearLog'
    ]),
    // 开始执行
    async start () {
      this.clearLog()
      if (this.selectList.length === 0) {
        this.addLogError(`请至少选择一条数据进行操作`)
        return
      }
      this.addLogWarning('开始执行，请勿随意操作页面')
      try {
        await this.build()
        await this.upload()
        await this.restart()
        this.activeStep = 0
      } catch (err) {
        this.addLogError(err)
        this.activeStep = 0
      }
    },
    // 本地打包
    build () {
      return new Promise(async (resolve, reject) => {
        try {
          this.activeStep++
          const startTime = new Date()
          const selectList = JSON.parse(JSON.stringify(this.selectList))
          for (let i = 0; i < selectList.length; i++) {
            this.addLog(`正在打包第${i + 1}个子路径「${selectList[i].configName}」...`)
            const config = selectList[i]
            const { buildPath, buildChild } = config
            await this.buildExec(buildChild, buildPath)
          }
          const endTime = new Date()
          const interval = (endTime - startTime) / 1000
          this.addLogSuccess(`打包完成，共耗时${interval}秒`)
          resolve(true)
        } catch (err) {
          reject(err)
        }
      })
    },
    // 执行本地打包命令
    buildExec (child, path) {
      return new Promise((resolve, reject) => {
        exec(`hui child --path ${child}`, { cwd: path }, (err, stdout, stderr) => {
          if (err) {
            this.addLogError('执行错误，请检查本地项目路径是否正确')
            return reject(err)
          }
          if (stdout) {
            if (stdout.indexOf('Error: Can\'t resolve') > -1) {
              this.addLogError('执行错误，请检查打包子路径是否正确')
              return reject(stdout)
            } else {
              resolve(true)
            }
          }
          if (stderr) {
            this.addLogWarning(stderr)
            return reject(stderr)
          }
        })
      })
    },
    // 上传到服务器
    upload () {
      return new Promise(async (resolve, reject) => {
        try {
          this.activeStep++
          const startTime = new Date()
          const selectList = JSON.parse(JSON.stringify(this.selectList))
          for (let i = 0; i < selectList.length; i++) {
            this.addLog(`正在上传第${i + 1}个文件夹「${selectList[i].configName}」...`)
            await this.uploadExec(selectList[i])
          }
          const endTime = new Date()
          const interval = (endTime - startTime) / 1000
          this.addLogSuccess(`上传完成，共耗时${interval}秒`)
          resolve(true)
        } catch (err) {
          reject(err)
        }
      })
    },
    // 执行上传命令
    uploadExec (config) {
      return new Promise(async (resolve, reject) => {
        try {
          let client = new Client()
          const connectConfig = {
            host: config.remoteAddress,
            port: '22',
            username: config.username,
            password: config.password
          }
          const localPath = `${config.buildPath}/hui-build/${config.buildChild}`
          const remotePath = `${config.webServerPath}/webapps/hsfa60/${config.buildChild}`
          this.addLog('本地地址：' + localPath)
          this.addLog('服务器地址：' + remotePath)
          await client.connect(connectConfig)
          await client.uploadDir(localPath, remotePath)
          client.end()
          resolve(true)
        } catch (err) {
          if (err.message.indexOf('authentication') > 0) {
            this.addLogError('远程服务器连接失败，请检查服务器相关内容是否填写正确')
          }
          if (err.message.indexOf('no such file or directory') > 0) {
            this.addLogError('没有找到文件夹，请检查路径是否正确')
          }
          reject(new Error('「上传到服务器」步骤出错'))
        }
      })
    },
    // 重启web服务器
    restart () {
      return new Promise(async (resolve, reject) => {
        try {
          this.activeStep++
          const startTime = new Date()
          const selectList = JSON.parse(JSON.stringify(this.selectList))
          for (let i = 0; i < selectList.length; i++) {
            this.addLog(`正在重启第${i + 1}个服务「${selectList[i].configName}」...`)
            await this.restartExec(selectList[i])
          }
          const endTime = new Date()
          const interval = (endTime - startTime) / 1000
          this.addLogSuccess(`重启完成，共耗时${interval}秒`)
          resolve(true)
        } catch (err) {
          reject(err)
        }
      })
    },
    // 执行重启命令
    restartExec (config) {
      return new Promise(async (resolve, reject) => {
        try {
          this.activeStep++
          const connectConfig = {
            host: config.remoteAddress,
            port: '22',
            username: config.username,
            password: config.password
          }
          const ssh = new SSH2Promise(connectConfig)
          await ssh.connect()
          await ssh.spawn(`cd ${config.webServerPath}`)
          await ssh.spawn('sh stop.sh')
          await ssh.spawn('sh start.sh')
          resolve(true)
        } catch (err) {
          reject(err)
        }
      })
    }
  }
}
</script>

<style lang="scss" scoped>
.operation-content{
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-evenly;
  height: 100%;
  width: 100%;
}
.step-content{
  .step-button{
    display: flex;
    align-items: center;
    position: relative;
    padding: 0 20px;
    height: 35px;
    font-size: 14px;
    color: #ccc;
    letter-spacing: .1em;
    font-family: PingFang SC, Microsoft YaHei;
    border: 1px solid #ccc;
    outline: none;
    background: #fff;
    border-radius: 2px;
    transition: all 0.3s linear;
    &.active{
      padding: 0 20px 0 30px;
      border: 1px solid $theme-color;
      color: $theme-color;
    }
    .iconfont{
      position: absolute;
      left: 10px;
      color: $theme-color;
      animation: rotate .8s ease-in-out infinite;
      &.actived{
        animation: none;
      }
    }
  }
}

@keyframes rotate {
  from { transform: rotate(0); }
  to { transform: rotate(360deg); }
}
</style>